#include "acceptor.h"
#include "eventloop.h"
#include "socket.h"
#include "channel.h"

#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <iostream>

Acceptor::Acceptor(EventLoop* loop, const std::string& ip, uint16_t port)
    : loop_(loop),
      listenSocket_(std::make_unique<Socket>(ip, port)),
      listenChannel_(std::make_unique<Channel>(loop, listenSocket_->fd())) {
    
    listenSocket_->setReuseAddr(true);
    listenSocket_->bind();

    listenChannel_->setReadCallback([this]() { handleRead(); });
}

Acceptor::~Acceptor() {
    listenChannel_->disableAll();
    listenChannel_->remove();
}

void Acceptor::listen() {
    listenSocket_->listen();
    listenChannel_->enableReading(); 
}

void Acceptor::setNewConnectionCallback(NewConnectionCallback cb) {
    newConnCallback_ = std::move(cb);
}

void Acceptor::handleRead() {
    sockaddr_in peerAddr {};
    socklen_t len = sizeof(peerAddr);
    int connfd = ::accept4(listenSocket_->fd(), (sockaddr*)&peerAddr, &len, SOCK_NONBLOCK | SOCK_CLOEXEC);

    if (connfd >= 0) {
        char ip[INET_ADDRSTRLEN];
        ::inet_ntop(AF_INET, &peerAddr.sin_addr, ip, sizeof(ip));
        uint16_t port = ntohs(peerAddr.sin_port);
        std::string peer = std::string(ip) + ":" + std::to_string(port);

        if (newConnCallback_) {
            newConnCallback_(connfd, peer);
        } else {
            ::close(connfd);
        }
    } else {
        std::cerr << "accept4 error: " << strerror(errno) << std::endl;
    }
}